#ifndef _LOCALPARTITIONCMP_H
#define _LOCALPARTITIONCMP_H


#include <stdint.h>

#include "CMP.h"
#include "LocalPartition.h"
#include "trace.h"
#include "memory.h"
#include "tlb.h"
#include "constants.h"
#include "ConfigParameter.hpp"

#include "../../engine/address.hpp"
#include "../../utils/libcache/CacheWriteBack.hpp"

/** This class represents a multicore based on LocaPartitions*/

class LocalPartitionCMP : public CMP {
    LocalPartition  *_LP[32];
    uint32_t *_LPHits;
    uint32_t *_LPRemoteHitsOnChip,*_LPRemoteHitsOffChip;
    uint32_t *_LPReplacementsOnChip,*_LPReplacementsOffChip;

    uint32_t _chips;
    uint32_t _threadsperchip;
    uint32_t _MultiFELI_policy;
    uint32_t _LMSize;
    uint32_t _threshold;
    uint32_t _InterChipThreshold;
    uint32_t _L0InvalidatePolicy;
    uint32_t _victimPolicy;
    void resetLocationResults();

    void reset();

  public:
    LocalPartitionCMP(uint32_t chips,uint32_t threadsperchip,uint32_t MultiFELI_policy,
                      uint32_t InterChipThreshold,
                      uint32_t threads,uint32_t pageSize,uint32_t lineSize,
                      uint32_t L0Size,uint32_t LMSize, uint32_t threshold,
                      uint32_t invalidatePolicy,uint32_t victimPolicy);
    ~LocalPartitionCMP();
    void execute(Memory * mem,Trace * trace,ConfigParameter conf);
    void executeMigrateonMutex(Memory * mem,Trace * trace);
    void invalidateL0(uint64_t replaced,uint32_t currentThread,bool isL0cached);
    void preAllocate(Memory * mem,Trace * trace,uint32_t policy);
    bool
        executeLPSimulation(Memory *mem,Trace *trace,uint32_t policy);
    uint32_t
        policyFirst(Memory * mem, uint32_t thread,uint32_t page,uint32_t access);
    uint32_t
        policyFirstThreshold(Memory * mem, uint32_t thread,uint32_t page,uint32_t access);
    uint32_t
        policyProfile(Memory * mem, Trace *trace,uint32_t thread,uint32_t page,uint32_t access);
    uint32_t
        policyProfileDynamic (Memory * mem,  Trace *trace,uint32_t thread,uint32_t page, uint32_t access);
    uint32_t
        policyWorkingSet(Memory * mem, Trace *trace, uint32_t thread, uint32_t page, uint32_t access);

    void migratePage(Memory * mem,uint32_t page,uint32_t location,uint32_t thread);
    bool isLocalChipLocation(uint32_t location,uint32_t thread);
    uint32_t getChipAccesses(Memory *mem, uint32_t thread,uint32_t page);

   /* FELI functionalities */
    uint32_t
        FELI_localChipAccess(Memory *mem,uint64_t & addr,address_t &physical,
                uint32_t & page,uint32_t thread,uint32_t opcode);
    uint32_t
    FELI_remoteChipAccess(Memory * mem,uint32_t location,address_t physical,
                      uint32_t page, uint32_t thread,uint32_t opcode);

    uint32_t
        policyFELI(Memory * mem, uint32_t currentThread, uint64_t addr, uint32_t access,uint32_t opcode);
    /* MultiFELI */
    uint32_t
        policyMultiFELI(Memory * mem, uint32_t currentThread, uint64_t addr, uint32_t access,uint32_t opcode);
    uint32_t
        MultiFELINormal(Memory * mem,uint32_t location,address_t physical,
                uint32_t page, uint32_t thread,uint32_t opcode);
    uint32_t
        MultiFELIFroze(Memory * mem,uint32_t location,address_t physical,
                uint32_t page, uint32_t thread,uint32_t opcode);
    uint32_t
        MultiFELIPivot(Memory * mem,uint32_t location,address_t physical,
                uint32_t page, uint32_t thread,uint32_t opcode);
    /* End of MultiFELI */



    uint32_t
        policyL1Cache(Memory * mem,  uint32_t thread, uint32_t page,uint32_t access);
    uint32_t
        policyL2Cache(Memory * mem,  uint32_t thread, uint32_t page,uint32_t access);
    uint32_t
        getLocation(Memory * mem, Trace *trace,uint32_t thread,uint64_t addr,
                uint32_t access,uint32_t policy,uint32_t opcode=0);
    inline uint32_t getLPHits(uint32_t tid)         const { return _LPHits[tid];}
    inline uint32_t getLPRemoteHitsOnChip(uint32_t tid)   const { return _LPRemoteHitsOnChip[tid];}
    inline uint32_t getLPRemoteHitsOffChip(uint32_t tid)   const { return _LPRemoteHitsOffChip[tid];}
    inline uint32_t getLPReplacementsOnChip(uint32_t tid) const { return _LPReplacementsOnChip[tid];}
    inline uint32_t getLPReplacementsOffChip(uint32_t tid) const { return _LPReplacementsOffChip[tid];}
    inline uint32_t getL0InvalidatePolicy()         const {  return _L0InvalidatePolicy; }
    inline uint32_t getVictimPolicy()               const {  return _victimPolicy; }
};
#endif
